"""Core game state container and helpers."""

from __future__ import annotations

from dataclasses import dataclass, field

from config import PLAYER_CONFIG, TIME_CONFIG


DAY_PHASE_SEQUENCE = ("day", "dusk", "night")


@dataclass
class GameState:
    inventory: dict[str, int] = field(default_factory=lambda: {
        "wood": 0,
        "stone": 0,
        "plank": 0,
        "ore_gem": 0,
        "stone_brick": 0,
    })
    health: int = PLAYER_CONFIG.max_health
    stamina: int = PLAYER_CONFIG.max_stamina
    enemy_system_active: bool = False
    time_elapsed: float = 0.0
    day_phase: str = "day"
    current_task: str | None = None
    task_progress: dict[str, int] = field(default_factory=dict)
    inventory_capacity: int | None = None

    def change_health(self, amount: int) -> None:
        self.health = max(0, min(PLAYER_CONFIG.max_health, self.health + amount))

    def consume_stamina(self, amount: int) -> bool:
        if self.stamina < amount:
            return False
        self.stamina = max(0, self.stamina - amount)
        return True

    def recover_stamina(self) -> None:
        if self.stamina < PLAYER_CONFIG.max_stamina:
            self.stamina = min(
                PLAYER_CONFIG.max_stamina,
                self.stamina + PLAYER_CONFIG.stamina_recovery_rate,
            )

    def total_items(self) -> int:
        return sum(self.inventory.values())

    def has_space_for(self, amount: int) -> bool:
        if amount <= 0:
            return True
        if self.inventory_capacity is None:
            return True
        return self.total_items() + amount <= self.inventory_capacity

    def add_item(self, item_type: str, amount: int = 1) -> bool:
        if amount <= 0:
            return True
        if self.inventory_capacity is not None and not self.has_space_for(amount):
            return False
        if item_type not in self.inventory:
            self.inventory[item_type] = 0
        self.inventory[item_type] += amount
        return True

    def remove_item(self, item_type: str, amount: int = 1) -> bool:
        if self.inventory.get(item_type, 0) < amount:
            return False
        self.inventory[item_type] -= amount
        if self.inventory[item_type] <= 0:
            self.inventory[item_type] = 0
        return True

    def has_items(self, requirements: dict[str, int]) -> bool:
        return all(self.inventory.get(name, 0) >= amount for name, amount in requirements.items())

    def consume_items(self, requirements: dict[str, int]) -> bool:
        if not self.has_items(requirements):
            return False
        for name, amount in requirements.items():
            self.remove_item(name, amount)
        return True

    def update_time(self, delta_seconds: float) -> None:
        self.time_elapsed += delta_seconds
        total_cycle = (
            TIME_CONFIG.day_length_seconds
            + TIME_CONFIG.dusk_length_seconds
            + TIME_CONFIG.night_length_seconds
        )
        time_in_cycle = self.time_elapsed % total_cycle
        if time_in_cycle < TIME_CONFIG.day_length_seconds:
            self.day_phase = "day"
        elif time_in_cycle < TIME_CONFIG.day_length_seconds + TIME_CONFIG.dusk_length_seconds:
            self.day_phase = "dusk"
        else:
            self.day_phase = "night"

    @property
    def is_alive(self) -> bool:
        return self.health > 0

    def toggle_enemy_system(self) -> None:
        self.enemy_system_active = not self.enemy_system_active
